package model

import (
	"database/sql"
	"fmt"
	"io"
	"maps"
	"net/http"
	"strings"
	"vector/tools"

	"gitee.com/jn-qq/big-model/common"
	"gitee.com/jn-qq/big-model/openai"
	"gitee.com/jn-qq/go-tools/data"
	_ "github.com/go-sql-driver/mysql"
)

// AgentModelTask Agent模型任务实现（模式9）
type AgentModelTask struct {
	content    string
	scene      string
	resultData map[string]any
}

func (a *AgentModelTask) Reset() {
	a.content = ""
	a.scene = ""
	clear(a.resultData)
}

// NewTaskData 初始化任务数据
func (a *AgentModelTask) NewTaskData(row map[string]any) error {
	a.resultData = maps.Clone(row)

	// 获取必要参数
	if scene, ok := row["场景"]; ok {
		a.scene = scene.(string)
	} else {
		a.resultData["备注"] = "缺少场景参数"
		return fmt.Errorf("缺少场景参数")
	}

	if content, ok := row["问题"]; ok {
		a.content = content.(string)
	} else {
		a.resultData["备注"] = "缺少问题参数"
		return fmt.Errorf("缺少问题参数")
	}

	return nil
}

// Do 执行Agent模型任务
func (a *AgentModelTask) Do() {
	result := map[string]any{"备注": "", "回复": ""}
	var step strings.Builder

	// 获取模型配置
	model, ok := tools.Config.Agent[a.scene]
	if !ok {
		result["备注"] = "未找到对应的模型配置"

		// 将结果合并到resultData中
		for key, value := range result {
			a.resultData[key] = value
		}
		return
	}

	client := openai.NewOpenAiClient(common.Model{
		Url:       model.Address,
		ApiKey:    model.ApiKey,
		ModelType: model.ModeType,
		IsReason:  false,
	}).
		SetStream(model.Stream).
		SetMaxRounds(model.MaxTokens).
		SetTemperature(model.Temperature).
		SetTopK(model.TopK).
		SetSystem(model.DefaultSystemPrompt)

	round := 1
	content := a.content
	isDebug := false

	for {
		writeAndPrint(&step, isDebug, "智能体第%d轮交互\n", round)
		round += 1

		response, err := client.Chat(content)
		if err != nil {
			result["备注"] = err.Error()
			break
		}

		var isBreak bool
		var action, parameter string
		for _, line := range strings.Split(response.GetAnswer(), "\n") {
			// 去除前后空格
			line = strings.TrimSpace(line)

			switch true {
			case strings.HasPrefix(line, "Thought:"):
				line = strings.TrimPrefix(line, "Thought: ")
				writeAndPrint(&step, isDebug, "智能体思考###: %s\n", line)
			case strings.HasPrefix(line, "Action:"):
				action = strings.TrimPrefix(line, "Action: ")
				writeAndPrint(&step, isDebug, "工具名称###: %s\n", action)
			case strings.HasPrefix(line, "Action_Parameter:"):
				parameter = strings.TrimPrefix(line, "Action_Parameter: ")
				writeAndPrint(&step, isDebug, "工具入参###: %s\n", parameter)
			case strings.HasPrefix(line, "Finish:"):
				isBreak = true
				line = strings.TrimPrefix(line, "Finish: ")
				writeAndPrint(&step, isDebug, "最终回复###: %s\n", line)
			default:
				continue
			}
		}
		if isBreak {
			break
		}

		// 调用工具,获取结果
		content = "Observation: "

		if customResponse := model.CustomResponse(action); customResponse != "" {
			content += customResponse
			writeAndPrint(&step, isDebug, "工具结果###: %s\n\n", customResponse)
			continue
		}
		if customResponse := sendToAgentTool(action, parameter); customResponse != "" {
			content += customResponse
			writeAndPrint(&step, isDebug, "工具结果###: %s\n\n", customResponse)
			continue
		}
		writeAndPrint(&step, isDebug, "工具结果###: null\n\n")
		break
	}

	result["回复"] = step.String()

	// 将结果合并到resultData中
	for key, value := range result {
		a.resultData[key] = value
	}
}

// Result 返回任务结果
func (a *AgentModelTask) Result() map[string]any {
	return maps.Clone(a.resultData)
}

// writeAndPrint 写入并打印内容
func writeAndPrint(str *strings.Builder, debug bool, format string, args ...any) {
	content := fmt.Sprintf(format, args...)
	str.WriteString(content)
	if debug {
		fmt.Printf(content)
	}
}

// readApiResource 读取API资源
func readApiResource() map[string][]string {
	// 调用数据库获取工具接口地址
	db, err := sql.Open("mysql", "root:MYSQL1.t!@#@tcp(172.31.205.27:3306)/spark_large_model?charset=utf8")
	if err != nil {
		panic(err)
	}
	defer db.Close() // 确保关闭连接
	rows, err := db.Query("SELECT api_name,base_url,api_path,invoke_method FROM t_agent_api_resource ")
	if err != nil {
		panic(err)
	}
	defer rows.Close() // 确保关闭结果集

	// 处理查询结果
	var result = make(map[string][]string)
	for rows.Next() {
		var apiName, baseUrl, apiApth, invokeMethod string
		if err = rows.Scan(&apiName, &baseUrl, &apiApth, &invokeMethod); err != nil {
			panic(err)
		}
		result[apiName] = []string{baseUrl, apiApth, invokeMethod}
	}

	return result
}

var apiResource map[string][]string

// sendToAgentTool 发送请求到Agent工具
func sendToAgentTool(apiName string, params string) string {
	if apiResource == nil {
		// 调用数据库获取工具接口地址
		apiResource = readApiResource()
	}
	api, ok := apiResource[apiName]
	if !ok {
		return ""
	}
	request, _ := http.NewRequest(api[2], api[0]+api[1], strings.NewReader(params))
	request.Header.Set("Content-Type", "application/json")
	request.Header.Set("phoneNumber", "19712329425")
	request.Header.Set("uiState", " YoYo")

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		return ""
	}
	defer response.Body.Close()
	body, err := io.ReadAll(response.Body)
	if err != nil {
		return ""
	}
	js := data.JsonString(body)
	answer, _ := js.Find("data.replyAnswer")
	if answer == nil {
		return string(body)
	}

	return answer.(string)
}
